package com.minidb.engine;

import com.minidb.utils.StatementType;

import java.util.List;

public class Executor {
    private StorageEngine storageEngine;
    private CatalogManager catalogManager;

    public Executor(StorageEngine storageEngine, CatalogManager catalogManager) {
        this.storageEngine = storageEngine;
        this.catalogManager = catalogManager;
    }

    // Execute the given execution plan and return the result (output or status message).
    public String executePlan(ExecutionPlan plan) {
        StatementType type = plan.type;
        if (type == StatementType.CREATE_TABLE) {
            // Create the table via CatalogManager
            boolean created = catalogManager.createTable(plan.tableName, plan.columns, plan.columnTypes);
            if (!created) {
                return "Error: Table " + plan.tableName + " already exists.";
            }
            return "Table " + plan.tableName + " created.";
        } else if (type == StatementType.INSERT) {
            // Perform the insert
            int count = storageEngine.insertRecord(plan.tableName, plan.values, plan.columns);
            return count + " row" + (count == 1 ? "" : "s") + " inserted.";
        } else if (type == StatementType.SELECT) {
            // Get all records from the table
            List<List<String>> records = storageEngine.selectAllRecords(plan.tableName);
            // Apply WHERE filter if present
            if (plan.condition != null) {
                records.removeIf(rec -> !catalogManager.evaluateCondition(plan.tableName, plan.condition, rec));
            }
            // Build output string (table header and rows)
            StringBuilder sb = new StringBuilder();
            // Determine which columns to output
            List<String> tableCols = catalogManager.getColumns(plan.tableName);
            List<String> outputCols = (plan.columns == null || plan.columns.isEmpty()) ? tableCols : plan.columns;
            // Header line
            sb.append(String.join(" | ", outputCols)).append("\n");
            // Data rows
            for (List<String> rec : records) {
                if (plan.columns != null && !plan.columns.isEmpty()) {
                    // Project only requested columns (in requested order)
                    String[] outValues = new String[outputCols.size()];
                    for (int i = 0; i < outputCols.size(); i++) {
                        int idx = tableCols.indexOf(outputCols.get(i));
                        outValues[i] = rec.get(idx);
                    }
                    sb.append(String.join(" | ", outValues));
                } else {
                    // No projection list (output all columns as stored)
                    sb.append(String.join(" | ", rec));
                }
                sb.append("\n");
            }
            // Footer: row count
            sb.append(records.size()).append(" row").append(records.size() == 1 ? "" : "s").append(" selected.");
            return sb.toString();
        } else if (type == StatementType.DELETE) {
            // Perform deletion
            int count = storageEngine.deleteRecords(plan.tableName, plan.condition);
            return count + " row" + (count == 1 ? "" : "s") + " deleted.";
        } else {
            return "Unsupported operation: " + type;
        }
    }
}
